package com.gitee.yusugar.pay.alipay.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.domain.*;

import java.util.Date;
import java.util.Map;

public class AlipayUtil {
    /**
     * 生成 32 位订单编号
     *
     * @return 订单编号
     */
    public static String generatorOrderNo32() {
        return DateUtil.format( new Date(), "yyMMddHHmmssSSS" ) + RandomUtil.randomString( 17 ).toUpperCase();
    }

    /**
     * 构建简单的App支付参数
     *
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradeAppPayModel sampleAppPay( String totalAmount, String subject ) {
        return sampleAppPay( generatorOrderNo32(), totalAmount, subject );
    }

    /**
     * 构建简单的App支付参数
     *
     * @param outTradeNo  订单编号
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradeAppPayModel sampleAppPay( String outTradeNo, String totalAmount, String subject ) {
        AlipayTradeAppPayModel alipayTradeAppPayModel = new AlipayTradeAppPayModel();

        alipayTradeAppPayModel.setOutTradeNo( StrUtil.isBlank( outTradeNo ) ? generatorOrderNo32() : outTradeNo );
        alipayTradeAppPayModel.setTotalAmount( totalAmount );
        alipayTradeAppPayModel.setSubject( subject );

        return alipayTradeAppPayModel;
    }

    /**
     * 构建简单的电脑网站支付参数
     *
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradePagePayModel samplePagePay( String totalAmount, String subject ) {
        return samplePagePay( generatorOrderNo32(), totalAmount, subject );
    }

    /**
     * 构建简单的电脑网站支付参数
     *
     * @param outTradeNo  订单编号
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradePagePayModel samplePagePay( String outTradeNo, String totalAmount, String subject ) {
        AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();

        alipayTradePagePayModel.setOutTradeNo( StrUtil.isBlank( outTradeNo ) ? generatorOrderNo32() : outTradeNo );
        alipayTradePagePayModel.setTotalAmount( totalAmount );
        alipayTradePagePayModel.setSubject( subject );
        alipayTradePagePayModel.setProductCode( "FAST_INSTANT_TRADE_PAY" );

        return alipayTradePagePayModel;
    }

    /**
     * 构建简单的手机网站支付参数
     *
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradeWapPayModel sampleWapPay( String totalAmount, String subject ) {
        return sampleWapPay( generatorOrderNo32(), totalAmount, subject );
    }

    /**
     * 构建简单的手机网站支付参数
     *
     * @param outTradeNo  订单编号
     * @param totalAmount 金额
     * @param subject     标题
     * @return 支付对象
     */
    public static AlipayTradeWapPayModel sampleWapPay( String outTradeNo, String totalAmount, String subject ) {
        AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();

        alipayTradeWapPayModel.setOutTradeNo( StrUtil.isBlank( outTradeNo ) ? generatorOrderNo32() : outTradeNo );
        alipayTradeWapPayModel.setTotalAmount( totalAmount );
        alipayTradeWapPayModel.setSubject( subject );

        return alipayTradeWapPayModel;
    }

    /**
     * 构建简单退款订单
     *
     * @param outTradeNo   订单号
     * @param refundAmount 退款金额
     * @return 退款对象
     */
    public static AlipayTradeRefundModel sampleRefund( String outTradeNo, String refundAmount ) {
        return sampleRefund( outTradeNo, refundAmount, null, null );
    }

    /**
     * 构建简单退款订单
     *
     * @param outTradeNo   订单号
     * @param refundAmount 退款金额
     * @param refundReason 退款原因
     * @return 退款对象
     */
    public static AlipayTradeRefundModel sampleRefund( String outTradeNo, String refundAmount, String refundReason ) {
        return sampleRefund( outTradeNo, refundAmount, refundReason, null );
    }

    /**
     * 构建简单退款订单
     *
     * @param outTradeNo   订单号
     * @param refundAmount 退款金额
     * @param outRequestNo 退款请求号
     * @return 退款对象
     */
    public static AlipayTradeRefundModel sampleRefundByRequestNo( String outTradeNo, String refundAmount, String outRequestNo ) {
        return sampleRefund( outTradeNo, refundAmount, null, outRequestNo );
    }

    /**
     * 构建简单退款订单
     *
     * @param outTradeNo   订单号
     * @param refundAmount 退款金额
     * @param refundReason 退款原因
     * @param outRequestNo 退款请求号
     * @return 退款对象
     */
    public static AlipayTradeRefundModel sampleRefund( String outTradeNo, String refundAmount, String refundReason, String outRequestNo ) {
        AlipayTradeRefundModel alipayTradePayModel = new AlipayTradeRefundModel();

        alipayTradePayModel.setOutTradeNo( outTradeNo );
        alipayTradePayModel.setRefundAmount( refundAmount );
        alipayTradePayModel.setRefundReason( refundReason );
        alipayTradePayModel.setOutRequestNo( outRequestNo );

        return alipayTradePayModel;
    }

    /**
     * 构建简单交易关闭参数
     *
     * @param outTradeNo 订单编号
     * @return 参数
     */
    public static AlipayTradeCloseModel sampleClose( String outTradeNo ) {
        AlipayTradeCloseModel alipayTradeCloseModel = new AlipayTradeCloseModel();

        alipayTradeCloseModel.setOutTradeNo( outTradeNo );
        return alipayTradeCloseModel;
    }

    /**
     * 构建简单查询订单参数
     *
     * @param outTradeNo 订单编号
     * @return 参数
     */
    public static AlipayTradeQueryModel sampleQuery( String outTradeNo ) {
        AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();

        alipayTradeQueryModel.setOutTradeNo( outTradeNo );
        return alipayTradeQueryModel;
    }

    /**
     * 构建简单退款查询订单参数
     *
     * @param outTradeNo 订单编号
     * @return 参数
     */
    public static AlipayTradeFastpayRefundQueryModel sampleRefundQuery( String outTradeNo ) {
        return sampleRefundQuery( outTradeNo, outTradeNo );
    }

    /**
     * 构建简单退款查询订单参数
     *
     * @param outTradeNo   订单编号
     * @param outRequestNo 退款请求号
     * @return 参数
     */
    public static AlipayTradeFastpayRefundQueryModel sampleRefundQuery( String outTradeNo, String outRequestNo ) {
        AlipayTradeFastpayRefundQueryModel alipayTradeFastpayRefundQueryModel = new AlipayTradeFastpayRefundQueryModel();

        alipayTradeFastpayRefundQueryModel.setOutTradeNo( outTradeNo );
        alipayTradeFastpayRefundQueryModel.setOutRequestNo( StrUtil.isBlank( outRequestNo ) ? outTradeNo : outRequestNo );

        return alipayTradeFastpayRefundQueryModel;
    }

    public enum NotifyState {

        /**
         * 支付成功
         */
        PAY_SUC,
        /**
         * 部分退款成功
         */
        PART_REFUND,
        /**
         * 全部退款成功
         */
        ALL_REFUND,
        /**
         * 订单超时关闭
         */
        TIME_OUT_CLOSE,
        /**
         * 用户支付成功且订单不支持退款
         */
        PAY_SUC_TRADE_FINISHED,
        /**
         * 订单完成（支持退款但，不能退款）
         */
        TRADE_FINISHED
    }

    /**
     * 判断支付宝异步回调状态(App、手机网站)
     *
     * @param alipayParams 支付宝异步回调参数
     * @return 状态
     */
    public static NotifyState judgeAppNotifyState( Map<String, String> alipayParams, boolean supportRefund ) {
        // 获取交易状态
        String tradeStatus = alipayParams.get( "trade_status" );
        // 获取退款金额
        String refundFee = alipayParams.get( "refund_fee" );

        if ( "TRADE_SUCCESS".equals( tradeStatus ) )
            // 若状态为 TRADE_SUCCESS，则代表该比交易是[用户支付成功(商户支持退款)/部分退款]
            // 退款金额为 null，则代表该比交易是支付，反之是部分退款
            return StrUtil.isBlank( refundFee ) ? NotifyState.PAY_SUC : NotifyState.PART_REFUND;
        else if ( "TRADE_CLOSED".equals( tradeStatus ) )
            // 若状态为 TRADE_CLOSED，则代表该比交易是[超时关闭/已全额退款]
            // 退款金额为 null，则代表该比交易是超时，反之是已全额退款
            return StrUtil.isBlank( refundFee ) ? NotifyState.TIME_OUT_CLOSE : NotifyState.ALL_REFUND;
        else if ( "TRADE_FINISHED".equals( tradeStatus ) )
            // 若状态为 TRADE_FINISHED，则代表该比交易是[用户支付成功但商户不支持退款/交易已经成功并且已经超过可退款期限]
            // 商户支持退款，则是交易完成。商户不支持退款，用户支付完成后，直接交易完成。
            return supportRefund ? NotifyState.TRADE_FINISHED : NotifyState.PAY_SUC_TRADE_FINISHED;
        else
            return null;
    }
}
